package com.pinguix.games.pong;

import danger.ui.Point;
import danger.ui.Rect;
import danger.ui.ScreenWindow;

public class CollisionManager
{
	private ScreenWindow _stage;
	private Ball _ball;
	private Paddle _p1;
	private Paddle _p2;

	private double _hSpeedBuildUp = 0.0;
	private double _vSpeedBuildUp = 0.0;
	
	public CollisionManager(ScreenWindow stage, Paddle p1, Paddle p2, Ball ball)
	{
		_stage = stage;
		_p1 = p1;
		_p2 = p2;
		_ball = ball;
	}

	public void addBall(Ball newBall)
	{
		_ball = newBall;
	}
	public void setPaddleLeft(Paddle newPaddle)
	{
		_p1 = newPaddle;
	}
	public void setPaddleRight(Paddle newPaddle)
	{
		_p2 = newPaddle;
	}
	
	private boolean overlapsLeft(Rect r1, Rect r2)
	{
		return(r1.right > r2.left && r2.right > r1.left);
	}
	private boolean overlapsRight(Rect r1, Rect r2)
	{
		return(r1.left < r2.right && r2.left < r1.right);
	}
	private boolean overlapsTop(Rect r1, Rect r2)
	{
		return(r1.top < r2.bottom && r2.top < r1.bottom);
	}
	private boolean overlapsBottom(Rect r1, Rect r2)
	{
		return(r1.bottom > r2.top && r2.top > r1.bottom);
	}
	
	//the reverse parameter will reverse true/false (to detect escape of stage collision)
	private boolean detectCollision(Rect r1, Rect r2, boolean reverse)
	{
		if(overlapsLeft(r1, r2) && (overlapsTop(r1,r2) || overlapsBottom(r1,r2)) ||
				overlapsRight(r1,r2) && (overlapsTop(r1,r2) || overlapsBottom(r1,r2)))
		{
			return true;
		}
		return false;
	}
	private void addBallSpeed(int vel)
	{
		_vSpeedBuildUp += vel/5.0;
		if(Math.abs(_vSpeedBuildUp) >= 1)
		{
			int temp = (int)(_vSpeedBuildUp);
			_vSpeedBuildUp -= temp;
			_ball.getVelocity().v += temp;
		}

		_hSpeedBuildUp += Math.abs(vel/10.0);
		if(_hSpeedBuildUp >= 1)
		{
			int temp = (int)(_hSpeedBuildUp);
			_hSpeedBuildUp -= temp;
			_ball.getVelocity().h += temp;
		}
	}
	private void executePaddleCollision()
	{
		boolean collidesAfterMove = false;
		boolean trueCollision = false;
		double th = _ball.getVelocityAngle();
		Rect bb = _ball.getBounds();
		Rect p1b = _p1.getBounds();
		Rect p2b = _p2.getBounds();

		//Check if ball collides w/ paddle 
		if(bb.right >= p2b.left && (bb.left - _ball.getVelocityMagnitude()*Math.cos(th)) <= p2b.right)
		{
			int deltaX = bb.right - p2b.left;

			//Check if collision occurs after passing point
			if(p2b.top < bb.bottom && p2b.bottom > bb.top && p2b.left <= bb.right && p2b.right >= bb.left)
				collidesAfterMove = true;
			
			//Move ball back to collision point for checking
			_ball.displace(-deltaX, (int)(-deltaX*Math.tan(th)));
			
			//Check if collision occurs at contact point
			if(!_ball.isDead() && p2b.top < bb.bottom && p2b.bottom > bb.top)
				trueCollision = true;
			
			if(trueCollision) //Move ball to where it should have gone w/ collision
			{
				_ball.getVelocity().h *= -1;
				_ball.displace(-deltaX, (int)(deltaX*Math.tan(th)));
				addBallSpeed(_p2.getVelocity().v);
			}
			else if(collidesAfterMove)//Bounce off paddle in to score zone
			{
				_ball.getVelocity().v *= -1;
				_ball.displace(deltaX, -(int)(deltaX*Math.tan(th)));
				_ball.kill();
			}
			else //No Collision (move ball back to where it went)
			{
				_ball.displace(deltaX, (int)(deltaX*Math.tan(th)));
				_ball.kill();
			}
		}
		else if(bb.left <= p1b.right && (bb.right +_ball.getVelocityMagnitude()*Math.cos(th)) >= p1b.left)
		{
			int deltaX = p1b.right - bb.left;
			
			if(p1b.top < bb.bottom && p1b.bottom > bb.top  && p1b.right >= bb.right && p1b.left <= bb.right)
				collidesAfterMove = true;
			
			_ball.displace(deltaX, (int)(deltaX*Math.tan(th)));
			
			if(!_ball.isDead() && p1b.top < bb.bottom && p1b.bottom > bb.top)
				trueCollision = true;
			
			if(trueCollision)
			{
				_ball.getVelocity().h *= -1;
				_ball.displace(deltaX, -(int)(deltaX*Math.tan(th)));
				addBallSpeed(_p1.getVelocity().v);
			}
			else if(collidesAfterMove)
			{
				_ball.getVelocity().v *= -1;
				_ball.displace(-deltaX, (int)(deltaX*Math.tan(th)));
				_ball.kill();
			}
			else
			{
				_ball.displace(-deltaX, -(int)(deltaX*Math.tan(th)));
				_ball.kill();
			}
			
		}
	}
	private void executeStageCollision()
	{
		Rect bb = _ball.getBounds();
		Rect stage = _stage.getBounds();
		
		if(bb.top <= stage.top)
		{
			int deltaY = stage.top - bb.top;
			_ball.displace(0 , 2*deltaY);
			_ball.getVelocity().v *= -1;
		}
		else if(bb.bottom >= stage.bottom)
		{
			int deltaY = bb.bottom - stage.bottom;
			_ball.displace(0 , -2*deltaY);
			_ball.getVelocity().v *= -1;
		}
	}
	
	public void update()
	{
		executeStageCollision();
		
		executePaddleCollision();
	}
}
